/*
 * 版权所有：义乌市路比信息科技有限公司
 * 作者：kinwyb<http://www.lcfgly.com>
 * 日期：2015-11-23
 */
package lcfgly.mybatis.auto;

import java.lang.reflect.Field;
import lcfgly.database.LSqlException;
import lcfgly.database.utils.LDataAnnotation;
import lcfgly.database.utils.LDataItemAnnotation;
import lcfgly.utils.LTypeUtils;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.jdbc.SQL;

/**
 * 自动生成代理SQL语句
 *
 * @author kinwyb<http://www.lcfgly.com>
 * @datetime 2015-11-23 13:54:56
 * @version 1.0
 */
public class BuildSql {

    /**
     * 生成SELECT语句
     * @param cs 反射对象类型
     * @param params 参数
     * @return
     * @throws LSqlException 
     */
    public static String select(Class cs, final MapperMethod.ParamMap params) throws LSqlException {
        LDataAnnotation tAnnotation = (LDataAnnotation) cs.getAnnotation(LDataAnnotation.class);
        if (tAnnotation == null || tAnnotation.value().trim().equals("")) {
            throw new LSqlException("数据实例 " + cs.getName() + " 不能获取到表名注解");
        }
        final String tablename = tAnnotation.value();
        Field[] fields = cs.getDeclaredFields();
        LDataItemAnnotation it;
        StringBuilder sdb = new StringBuilder();
        for (Field field : fields) {
            it = field.getAnnotation(LDataItemAnnotation.class);
            if (it != null) {
                sdb.append((it.item().trim().equals("")) ? field.getName() : it.item());
                sdb.append(",");
            }
        }
        final String columns = sdb.substring(0, sdb.length() - 1);
        final String where;
        if (params.containsKey("where") && params.get("where") != null) {
            if (!params.get("where").toString().isEmpty()) {
                where = params.get("where").toString();
            } else {
                where = null;
            }
        } else {
            where = null;
        }
        String sql = new SQL() {
            {
                SELECT(columns);
                FROM(tablename);
                if (where != null) {
                    WHERE(where);
                }
            }
        }.toString();
        if (params.containsKey("ext") && params.get("ext") != null) {
            sql = sql + params.get("ext").toString();
        }
        return sql;
    }

    /**
     * 生成单条SELECT
     * @param cs 反射对象类型
     * @param params
     * @return
     * @throws LSqlException 
     */
    public static String selectOne(Class cs, final MapperMethod.ParamMap params) throws LSqlException {
        String sql = select(cs, params);
        return sql += " LIMIT 1";
    }

    /**
     * 生成INSERT语句
     * @param ob 反射对象
     * @return
     * @throws LSqlException 
     */
    public static String insert(Object ob) throws LSqlException {
        Class cs=ob.getClass();
        LDataAnnotation tAnnotation = (LDataAnnotation) cs.getAnnotation(LDataAnnotation.class);
        if (tAnnotation == null || tAnnotation.value().trim().equals("")) {
            throw new LSqlException("数据实例 " + cs.getName() + " 不能获取到表名注解");
        }
        final String tablename = tAnnotation.value();
        Field[] fields = cs.getDeclaredFields();
        LDataItemAnnotation it;
        StringBuilder columns = new StringBuilder();
        StringBuilder values = new StringBuilder();
        for (Field field : fields) {
            it = field.getAnnotation(LDataItemAnnotation.class);
            if(it == null) //没有注解信息，跳过
                continue;
            Object item;
            try {
                field.setAccessible(true); //设置权限
                item = field.get(ob);
            } catch (IllegalArgumentException | IllegalAccessException ex) {
                throw new LSqlException("SQL对象解析失败", ex);
            }
            if(item == null){
                if(it.notnull())
                    throw new LSqlException(cs.getName() + "中" + field.getName() + "不能为空！");
                else
                    continue;//如果对象为空，不进行更新
            }
            if (!it.autokey()) {
                columns.append((it.item().trim().equals("")) ? field.getName() : it.item());
                columns.append(",");
                values.append("#{").append(field.getName()).append("},");
            }
        }
        final String column = columns.substring(0, columns.length() - 1);
        final String value = values.substring(0, values.length() - 1);
        return new SQL() {
            {
                INSERT_INTO(tablename);
                VALUES(column, value);
            }
        }.toString();
    }

    /**
     * 生成UPDATE语句
     * @param cs 反射对象类型
     * @param ob
     * @return
     * @throws LSqlException 
     */
    public static String update(Object ob) throws LSqlException {
        Class cs=ob.getClass();
        LDataAnnotation tAnnotation = (LDataAnnotation) cs.getAnnotation(LDataAnnotation.class);
        if (tAnnotation == null || tAnnotation.value().trim().equals("")) {
            throw new LSqlException("数据实例 " + cs.getName() + " 不能获取到表名注解");
        }
        final String tablename = tAnnotation.value();
        Field[] fields = cs.getDeclaredFields();
        LDataItemAnnotation it;
        StringBuilder set = new StringBuilder();
        StringBuilder where = new StringBuilder();
        for (Field field : fields) {
            it = field.getAnnotation(LDataItemAnnotation.class);
            if(it == null) //没有注解信息，跳过
                continue;
            Object item;
            try {
                field.setAccessible(true);
                item = field.get(ob);
            } catch (IllegalArgumentException | IllegalAccessException ex) {
                throw new LSqlException("SQL对象解析失败", ex);
            }
            if(item == null){
                if(it.notnull())
                    throw new LSqlException(cs.getName() + "中" + field.getName() + "不能为空！");
                else
                    continue;//如果对象为空，不进行更新
            }
            if (!it.primarykey()) {
                set.append((it.item().trim().equals("")) ? field.getName() : it.item());
                set.append(" = ").append("#{").append(field.getName()).append("},");
            } else if (it.primarykey()) {
                where.append((it.item().trim().equals("")) ? field.getName() : it.item());
                where.append(" = #{").append(field.getName()).append("}");
            }
        }
        if (where.length() < 1) {
            throw new LSqlException("类型 " + cs.getName() + " 自动生成UPDATE语句无法获取更新条件(无主键信息)");
        }
        final String st = set.substring(0, set.length() - 1);
        final String we = where.toString();
        if(LTypeUtils.stringIsEmpty(we))
            throw new LSqlException("无法获取条件约束,更新中断");
        return new SQL() {
            {
                UPDATE(tablename);
                SET(st);
                WHERE(we);
            }
        }.toString();
    }

    /**
     * 自动生成删除语句，根据注解中的主键作为删除条件
     * @param cs 反射对象类型
     * @return
     * @throws LSqlException
     */
    public static String delete(Class cs) throws LSqlException {
        LDataAnnotation tAnnotation = (LDataAnnotation) cs.getAnnotation(LDataAnnotation.class);
        if (tAnnotation == null || tAnnotation.value().trim().equals("")) {
            throw new LSqlException("数据实例 " + cs.getName() + " 不能获取到表名注解");
        }
        final String tablename = tAnnotation.value();
        Field[] fields = cs.getDeclaredFields();
        LDataItemAnnotation it;
        StringBuilder where = new StringBuilder();
        for (Field field : fields) {
            it = field.getAnnotation(LDataItemAnnotation.class);
            if (it != null && it.primarykey()) {
                where.append((it.item().trim().equals("")) ? field.getName() : it.item());
                where.append(" = #{").append(field.getName()).append("}");
                break;
            }
        }
        if (where.length() < 1) {
            throw new LSqlException("类型 " + cs.getName() + " 自动生成DELETE法获取删除条件(无主键信息)");
        }
        final String we = where.toString();
        if(LTypeUtils.stringIsEmpty(we))
            throw new LSqlException("无法获取条件约束,更新中断");
        return new SQL() {
            {
                DELETE_FROM(tablename);
                WHERE(we);
            }
        }.toString();
    }

    /**
     * 生成统计语句
     * @param cs 反射对象类型
     * @param params 参数
     * @return
     * @throws LSqlException 
     */
    public static String count(Class cs,final MapperMethod.ParamMap params) throws LSqlException {
        LDataAnnotation tAnnotation = (LDataAnnotation) cs.getAnnotation(LDataAnnotation.class);
        if (tAnnotation == null || tAnnotation.value().trim().equals("")) {
            throw new LSqlException("数据实例 " + cs.getName() + " 不能获取到表名注解");
        }
        final String tablename = tAnnotation.value();
        final String where;
        if (params.containsKey("where") && params.get("where") != null) {
            if (!params.get("where").toString().isEmpty()) {
                where = params.get("where").toString();
            } else {
                where = null;
            }
        } else {
            where = null;
        }
        String sql = new SQL() {
            {
                SELECT("COUNT(1)");
                FROM(tablename);
                if (where != null) {
                    WHERE(where);
                }
            }
        }.toString();
        if (params.containsKey("ext") && params.get("ext") != null) {
            sql = sql + params.get("ext").toString();
        }
        return sql;
    }

}
